﻿#define _CRT_SECURE_NO_WARNINGS 1



//sqrt 求平方根，头文件#include<math.h>,在网站前面加zh就说中文
 //写一个加法函数，完成2个整型变量的加法操作。
//int Add(int x, int y)
//{
//	//第一种写法
//	/*int z = 0;
//	z = x + y;
//	return z;*/
//	//第二种写法
//	return x + y;
//}
//int main()
//{
//	int a = 0;
//	int b = 0;
//	scanf("%d %d", &a, &b);
//	int c = Add(a, b);
//	printf("%d\n", c);
//	return 0;
//}
 
//return 在使用时

//void print(int n)
//{
//   if(n<0)
//     break;
//}//这是一种错误的写法，因为n<0时，不需要返回值所以用return; //break:是用在循环语句里面

//void print(int n)//正确写法
//{
//   if(n<0)
//     return;
//}    
// return语句执⾏后，函数就彻底返回，后边的代码不再执⾏。

// 如果函数中存在if等分⽀的语句，则要保证每种情况下都有return返回，否则会出现编译错误。
//错误示范
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//int test(int n)
//{
//if(n<0)
//	return 1;//会生成随机一串数字，不会按要求返回0就会出现编译器错误
//}
//
//int main()
//int r=test(10);
//printf("%d\n",r);
//
//
//return 0;
//}

//正确示范
//int test(int n)
//{
//if(n<0)
//	return 1;//要写完整才能运行成功
//else
//	return -1;
//}
//
//int main()
//{
//int r=test(10);
//printf("%d\n",r);
//
//
//return 0;
//}

//如果一个函数有明确的返回类型，但是函数内部没有return 返回值，最终返回什么值，是不确定的
//函数的返回类型如果不写的话，编译器会默认他返回值的是int类型

//为什么形参的数组不指定大小

//写⼀个函数将⼀个整型数组的内容，全部置为-1，再写⼀个函数打印数组的内容。

//void set_arr(int arr[], int sz)
//{
//	int i = 0;
//	for (i = 0; i < sz; i++)
//	{
//		arr[i] = -1;
//	}
//}
//void print_arr(int arr[], int sz)
//{
//	int i = 0;
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//
//}
//int main()
//{
//	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	print_arr(arr, sz);
//	set_arr(arr, sz);//set_arr函数要能够对数组内容进⾏设置
//	print_arr(arr, sz);//打印数组内容
//	return 0;
//}
//需要注意的问题：
//1.为什么形参的数组不指定大小
//数组传参，其实是传递是数组的地址，在形参部分访问数组的时候，其实是操作的是主调函数中的数组
//
//2.set_arr中修改的数组是主调函数中的arr吗
//数组传参的时候，在形参的部分不会新建数组，所以也就需要数组的大小


//假设我们计算某年某月有多少天？
//12个月的日期
//31 28 31 30 31 30 31 31 30 31 30 31
//   29 

//int is_leap_year(int y)
//{
//	if ((y % 400 == 0) || (y % 4 == 0) && (y % 100 == 0))
//		return 1;
//	else
//		return 0;
//
//}
//
//int get_day_of(int y, int m)
//{
//	int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//建立13个元素是因为下标是从0开始，这样多创建是方便输入数据时能对应上
//	int d = days[m];
//	if (is_leap_year(y) && m == 2)
//		d += 1;
//	return  d;
//}
//
//int main()
//{
//	int year = 0;
//	int month = 0;
//	scanf("%d %d", &year, &month);
//	int day = get_day_of(year, month);
//	printf("%d ", day);
//
//	return 0;
//}

//#include "add.h"
//int main()
//{
//	int a = 10;
//	int b = 20;
//	//函数调用
//	int c = Add(a, b);
//	printf("%d\n", c);
//	return 0;
//}

//extern int g_val;
//int main()
//{
//		printf("%d\n", g_val);
//		return 0;
//}

//extern int Add(int x, int y);
//int main()
//{
//	printf("%d\n", Add(2, 3));
//	return 0;
//}


//函数递归
//求第n个斐波那契数
//1 1 2 3 5 8 13 21 34 55......
//第一个数：1
//第二个数：1+0=1
//第三个数：1+1=2
//第四个数：1+2=3
//第五个数：2+3=5
//第六个数：3+5=8
//第七个数：5+8=13
//第八个数：8+13=21
//第九个数：13+21=34
//第十个数：21+34=55
//...
//第n个数：（n-1）+(n-2)=n

//int Fib(int n)
//{
//	if (n <= 2)
//		return 1;
//	else
//		return Fib(n - 1) + Fib(n - 2);
//}
//
//int main()
//{
//	int n = 0;
//	scanf("%d", &n);
//	int r = Fib(n);
//	printf("%d\n", r);
//	return 0;
//}
//但是上面的代码，会出问题，输入50时，运行结果慢且是错误结果
//因为50—> 49    +    48   49->48+47  48->47+46  
//          |            |
//         48+47      47+46
//         |   |      |   |
//   47+46  46+45  46+45  45+44
// ......
//我们会发现出现大量数据重复运算，如：count=39088169,意思是把第3个斐波那契数重复计算39088169次
//int count = 0;
//int Fib(int n)
//{
//	if (n == 3)
//		count++;
//	if (n <= 2)
//		return 1;
//	else
//		return Fib(n - 1) + Fib(n - 2);
//}
//
//int main()
//{
//	int n = 0;
//	scanf("%d", &n);
//	int r = Fib(n);
//	printf("%d\n", r);
//	printf("count=%d\n", count);
//	return 0;
//}
//因此，使用递归方法并不是适用于全部代码中，所以不要过于迷恋递归方法
//下面不使用递归方法，用循环方法
//设a=1,b=1,c=a+b
//原来是第一个数为a，第二个数为b：现在把第二个数变成a,第三个数相当于把c换成b，第四个数就是c=a+b，依此类推
//1 1 2 3 5 8 13 21 34 55......
//第一个数：1
//第二个数：1+0=1
//第三个数：1+1=2
//第四个数：1+2=3
//          a+b=c
//第五个数：2+3=5
//          a+b=c(把上面的b的值赋给下面的a，把上面的c的值赋给下面的b，则得到新的a,b，新的a,b相加得到新的c)
//第六个数：3+5=8
//第七个数：5+8=13
//第八个数：8+13=21
//第九个数：13+21=34
//第十个数：21+34=55
//...
//第n个数：（n-1）+(n-2)=n

//int Fib(int n)
//{
//	int a = 1;
//	int b = 1;
//	int c = 0;
//	if (n <= 2)
//		return 1;
//	while (n > 2)
//	{
//		c = a + b;
//		a = b;
//		b = c;
//		n--;//将 n 的值减 1。这是为了逐步接近目标位置 n。
//	}
//	return c;
//}
//
//int main()
//{
//	int n = 0;
//	scanf("%d", &n);
//	int r = Fib(n);
//	printf("%d\n", r);
//	return 0;
//}
//会出数字大结果错的现象，是因为数字结果太大了

//青蛙跳台阶问题
//一只青蛙，一次可以跳1个台阶，也可以跳两个台阶，问，这只青蛙，跳到第n个台阶，有多少种跳法
//最后一次跳台阶，有两种跳法；跳到第n个台阶时，在之前有n-1个台阶所以有n-1个跳法，在从n-1个台阶时，有n-2个台阶，则有n-2个跳法
//所以n=(n-1)+(n-2)个跳法，但第一个台阶有一种跳法，第二个台阶有二种跳法

//看比特大博哥



//操作符
//
//int main()
//{
//	printf("%d\n", 15);
//	printf("%d\n", 0xF);//十六进制
//	printf("%d\n", 017);//八进制
//	return 0;
//}

//int fun()
//{
//	static int count = -1;
//	//static可以使count在这里里面累积数值继续计算
//	return ++count;
//}
//
//int main()
//{
//	int answer;
//	answer = fun() - fun() * fun();
//	//       4     -  2    *  3 = -2
//	//       2     -  3    *  4 = -10
//	//       3     -  2    *  4 = -5
//	//会出现几种不同的值，所以优先性，结合性要慎用
//	printf("%d\n", answer);
//	return 0;
//}

//int main()
//{
//	int i = 1;
//	int ret = (++i) + (++i) + (++i);
//	printf("%d\n", ret);//ret的值在不同编译器下是不一样的，在VS2019里面为12，在dec++里面为10
//	printf("%d\n", i);
//	return 0;
//}


//int main()
//{
//	int n = 20;
//	char ch = 't';
//	int* pn = &n;
//	char* pi = &ch;
//	//pn是指针变量，是用来存放地址的，地址=指针
//	//int说明pn指向的对象是int类型，*说明pn是指针变量
//    printf("%d\n", *pn);
//	printf("%c\n", *pi);
//	return 0;
//}
//* --解引用操作符- 间接访问操作符

//注意指针变量的⼤⼩和类型是⽆关的，只要指针类型的变量，在相同的平台下，⼤⼩都是相同的。
//int main()
//{
//	printf("%zd\n", sizeof(char*));
//	printf("%zd\n", sizeof(short*));
//	printf("%zd\n", sizeof(int*));
//	printf("%zd\n", sizeof(double*));
//
//	return 0;
//}

//指针类型决定在对指针进行解引用操作的时候，访问几个字节
//char*--解引用访问1个字节
//int*--解引用访问4个字节
//short*--解引用访问2个字节

//int main()
//{
//	int n = 0x11223344;
//	int* pi = &n;
//	char* pc = &n;
//	printf("&n  =%p\n", &n);
//	printf("pi  =%p\n", pi);
//	printf("pi+1=%p\n", pi+1);
//	printf("pc  =%p\n", pc);
//	printf("pc+1=%p\n", pc+1);
//	return 0;
//}

//void* 是无具体类型的指针,可以接收不同类型的地址，但是无法直接进行指针运算
//int main()
//{
//	int n = 10;
//	void* pv = &n;//当我们想强制性把int转换成char，就可以写成void*
//	*(int*)pv = 200;
//	printf("%d\n", n);
//
//	//不可以写成：
//	//*pv=20;
//	return 0;
//}

//const修饰指针
//int const * p;//const 放在*的左边做修饰,如：

//int main()
//{
//	//int num = 100;
//	//int * p = &num;
//	//*p = 20;
//	//printf("%d\n", num);//可以改
//
//	//加const *
//	//int a = 10;
//	//int num = 100;
//	//int const* p = &num;
//	////*p = 20;//因为有const，把值固定了，不能通过*p=20，这种赋值方式改变
//	//printf("%d\n", num);
//
//	//加*  const
//	//int a = 10;
//	//int num = 100;
//	//int* const p = &num;
//	////*p = 20;//可以改变值
//	////p = &a;//不可以改变
//	//printf("%d\n", num);
//
//	//两边都加const  int const *const p
//	//int num = 100;
//	//int const* const p = &num;
//	//*p=20;
//	//p=&a;
//	//这两个都不可以改
//	//printf("%d\n", &num);
//	return 0;
//}


//指针运算
//指针+-整数

//写法一
//int main()
//{
	//int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//int* p = &arr[0];
	//int i = 0;
	//int sz = sizeof(arr) / sizeof(arr[0]);
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", *p);
//		p++;
//	}
//
//	return 0;
//}

//写法二
//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int* p = &arr[0];
//	int i = 0;
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", *(p + i));
//	}
//	return 0;
//}

	//for (i = 0; i < sz; i++)
	//{
	//	printf("%d ", arr[i]);
	//}//原来方法
//我们可以发现，学了指针，我们就可以用多种方法对数组进行有序打印

//对数组进行逆序打印
// 写法一
//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int* p = &arr[0];
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	for (int i = sz - 1; i >= 0; i--)
//	//i=sz-1意思是，sz是元素个数，元素个数有10个，而最大下标是9，i要从下标为9开始所以sz-1
//	{
//		printf("%d ", *(p + i));
//	}
//
//	return 0;
//}

//写法二
//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//    int* p = &arr[sz-1];
//	for (int i = 0; i < sz; i++)
//	{
//		printf("%d ", *p);
//		p--;
//	}
//
//	return 0;
//}


//指针-指针-->两者相减的绝对值能得到指针与指针之间的元素个数
//但运算前提条件是：两个指针指向同一块空间

//int main()
//{
//	int arr[10] = { 0 };
//	printf("%d\n", &arr[9] - &arr[0]);
//	//错误写法：
//	// 一个是字符型数组，一个是整型数组，两个数组不在同一个空间，则相减是会报错是错误的语法形式
//	//char arr1[10];
//	//int arr2[10];
//	//&arr2[8] - &arr1[5];
//	return 0;
//}

//求字符串长度
#include <string.h>
//size_t my_strlen(char* s)//方法一
//{
//	size_t count = 0;
//	while (*s != '\0')//当*s中的一个字符不等于'\0'时，就计数一次，s数组也加一次也就是s向前移动一位，指向下一个字符
//	{
//		count++;
//		s++;
//	}
//	return count;//返回计数的次数，就表示字符串的长度
//}

//size_t my_strlen(char* s)
//{
//	char* start = s;//创建一个指针变量，将其初始化，这样指针变量就是指向字符串的起始位置
//	while (*s != '\0')
//	{
//		s++;
//	}
//	return s - start;//返回s-start的结果，即字符串的长度
//
//}
//
//int main()
//{
//	char arr[] = "tyshizuibangde";
//	printf("%s\n", arr);
//	size_t len = my_strlen(arr);//类似于：arr==&arr[0]
//	printf("字符串长度=%zd\n", len);
//	return 0;
//}


//使用指针的关系运算来打印数组的内容
//int main()//顺序
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int* p = arr;
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	while (p < &arr[sz])
//	{
//		printf("%d ", *p);
//		p++;
//	}
//	return 0;
//}

//int main()//逆序
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	int* p = &arr[sz-1];
//	while (p >= &arr[0])
//	{
//		printf("%d ", *p);
//		p--;
//	}
//
//	return 0;
//}


//野指针
//1.指针未初始化，如：
//int main()
//{
//	int* p;//局部变量指针未初始化，默认为随机值
//	*p = 20;//非法访问， p就是野指针
//	printf("%d ", *p);
//	return 0;
//}

//2.指针越界访问
//int main()
//{
//	int arr[10] = { 0 };
//	int* p = &arr[0];
//	int i = 0;
//	for (i = 0; i <= 11; i++)
//	{
//		*(p++) = i;//当指针指向的范围超出数组arr的范围时，p就是野指针
//	}
//	/*for (i = 0; i <=11; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//	printf("\n");*/
//	return 0;
//}

//3.指针指向的空间释放
//int* test()
//{
//    int n = 100;
//    return &n;
//}
//
//int main()
//{
//    int* p = test();
//    printf("%d\n", *p);
//    return 0;
//}
//return &n 把地址传到main函数中，但上面n的空间就被释放，内存虽在但无法访问

//如何避免野指针出现
//1.指针初始化
//int main()
//{
//	int a = 10;
//	int* p1 = &a;//给指针变量一个明确的指向
//	int* p2 = NULL;//NULL空指针
//	//if (p2 != NULL)
//	//{
//	//	*p2 = 200;
//	//}
//	//printf("%d\n", *p1);
//	//printf("%d\n", *p2);
//	return 0;
//}
//注：'\0'是转义字符表示0；NULL是空指针也表示0；而0就是数字0；'0'是字符0在ASCII中的值为48

//assert断言
//size_t my_strlen(char* s)
//{
//	int count = 0;
//	assert(s != NULL);
//	while (*s)
//	{
//		count++;
//		s++;
//	}
//	return count;
//}
//
//int main()
//{
//	char arr[] = "hjhshisb";
//	printf("%s\n", arr);
//	size_t len = my_strlen(arr);
//	printf("%zd\n", len);
//	return 0;
//}

//#define NDEBUG//不使用assert就可以使用这个宏来禁用文件中assert的语句
//#include<assert.h>
//size_t my_strlen(char* s)//const使指针变量的值固定无法改变
//{
//	int count = 0;
//	assert(s != NULL);
//	while (*s)
//	{
//		count++;
//		s++;
//	}
//	return count;
//}
//
//int main()
//{
//	char arr[] = "hjhshisb";
//	printf("%s\n", arr);
//	size_t len = my_strlen(arr);
//	printf("%zd\n", len);
//	return 0;
//}


//写⼀个函数，交换两个整型变量的值

//void swap(int x, int y)
//{
//	int z = 0;
//	z = x;
//	x = y;
//	y = z;
//}
//上面的写法进行调试后，我们发现交换前后无变化，值发生变化但是地址并没有传过去导致结果无变化，这种写法不可行
//
//void swap2(int* pa, int* pb)
//{
//	int z = 0;
//	z = *pa;
//	*pa = *pb;
//	*pb = z;
//}
//经过调试后，交换值成功，这就是把swap2中的地址成功传到函数里面，这就是传址调用
//int main()
//{
//	int a = 0;
//	int b = 0;
//	scanf("%d %d", &a, &b);
//	printf("交换前:a=%d b=%d\n", a, b);
//	/*swap1(a, b);*///swap是交换的意思
//	swap2(&a, &b);
//	printf("交换后:a=%d b=%d\n", a, b);
//	return 0;
//}


//传值调用：
//int Add(int x, int y)
//{
//	int z = 0;
//	z = x + y;
//	return z;
//}
//
//int main()
//{
//	int a = 0;
//	int b = 0;
//	scanf("%d %d", &a, &b);
//	int r=Add(a, b);
//	printf("%d\n", r);
//	return 0;
//}


//数组名的理解
//int main()
//{
//	int arr[10] = { 0 };
//	printf("&arr[0]=%p\n", &arr[0]);
//	printf("arr    =%p\n", arr);
//	return 0;
//}
//数组名就是数组首元素(第一个元素)的地址。

//两个例外：
//1.sizeof(数组名)，sizeof中单独放数组名，这里的数组名表示整个数组，计算的是整个数组的大小，单位是字节
//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	printf("%d\n", sizeof(arr));//打印结果是40
//	return 0;
//}

//2.&数组名(&arr)，这里的数组名表示整个数组，取出的是整个数组的地址（整个数组的地址和数组首元素的地址是有区别的）

//int main()
//{
//	int arr[10] = { 0 };
//	printf("&arr[0] = %p\n", &arr[0]);//是int * 类型
//	printf("arr     = %p\n", arr);//是int * 类型
//	printf("&arr    = %p\n", &arr);
//	return 0;
//}
//上面的打印结果都是一样的

//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	printf("&arr[0]   = %p\n", &arr[0]);
//	printf("&arr[0]+1 = %p\n", &arr[0] + 1);//&arr[0]+1与&arr[0]相比，相差4个字节
//	printf("arr       = %p\n", arr);
//	printf("arr+1     = %p\n", arr + 1);//arr+1与arr相比，相差4个字节
//	printf("&arr      = %p\n", &arr);
//	printf("&arr+1    = %p\n", &arr + 1);//&arr+1与&arr相比，相差40个字节，相当于跳过了整个数组
//	return 0;
//}


//使用指针访问数组
//1.老方法：
//int main()
//{
//	int arr[10] = { 0 };
//	int i = 0;
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	for (i = 0; i < sz; i++)
//	{
//		scanf("%d", &arr[i]);//数组的输入
//	}
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//	return 0;
//}

//2.新方法一：
//int main()
//{
//	int arr[10] = { 0 };
//	int i = 0;
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	int* p = arr;
//	//arr 是数组名，数组名是数组首元素的地址
//	//则p为数组首元素的地址
//	for (i = 0; i < sz; i++)
//	{
//		scanf("%d", p + i);//数组的输入,p+i 就是下标为i元素的地址
//	}
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", *(p + i));
//		//printf("%d ", *(arr+i));
//		//printf("%d ", arr[i]);
//		//printf("%d ", p[i]);
//	}
//	//arr[i] ---*(arr+i) 完全等价的
//	//arr[i] 这种写法，编译器在执行的时候，也会转换成* (arr + i)的方式执行
//	return 0;
//}

//3.新方法二：
//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int i = 0;
//	int* p = arr;
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", *(p + i));
//		//printf("%d ", *(arr + i));
//		//printf("%d ", *(i+arr));
//		//printf("%d ", p[i]);
//		//printf("%d ", arr[i]);
//		//printf("%d ", i[arr]);//不推荐这种写法，但是可以了解
//	}
//
//	return 0;
//}
//arr[i] -- *(arr+i) -- *(i+arr) -- i[arr] 全部都相等


//一维数组传参的本质
//void test(int arr[10])//int arr[10]==int* arr
//{
//	int sz2 = sizeof(arr) / sizeof(arr[0]);
//	printf("sz2=%d\n", sz2);
//}
//
//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int sz1 = sizeof(arr) / sizeof(arr[0]);
//	printf("sz1=%d\n", sz1);
//	test(arr);
//	return 0;
//}
//调试出来的结果，显示sz1=10;sz2=1，为什么在主函数中的参数没有成功传到函数里
//因为在test(arr)中的arr是数组名，是数组首元素的地址
//所以数组传参传递的就是首元素的地址
//1. 函数形参的部分是不会真实创建数组的，那么就不需要数组大小
//2. 函数形参部分应该使用指针变量来接收 int* p;

//改进，让主函数中的参数传到函数里
//void test(int* arr, int sz)
//{
//	int sz2 = sz;
//	printf("sz2=%d\n", sz);
//}

//用传参来打印数组
//void test(int arr[10], int sz) //int* arr
//{
//	//遍历数组
//	int i = 0;
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//}

//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	printf("sz1=%d\n", sz);
//	test(arr, sz);
//	return 0;
//}


//冒泡排序
//      3, 9, 5, 2, 4, 8, 6, 0, 7, 1
// 下标:0, 1, 2, 3, 4, 5, 6, 7, 8, 9
// 对上面数组中的十个数字进行升序
// 
// 3和9比较,9大就在3后面：3, 9, 5, 2, 4, 8, 6, 0, 7, 1
// 9和5比较，9大在5后面：3, 5, 9, 2, 4, 8, 6, 0, 7, 1
// 9和2比较，9大在2后面：3, 5, 2, 9, 4, 8, 6, 0, 7, 1
// 9和4比较，9大在4后面：3, 5, 2, 4, 9, 8, 6, 0, 7, 1
// 9和8比较，9大在8后面：3, 5, 2, 4, 8, 9, 6, 0, 7, 1
// 9和6比较，9大在6后面：3, 5, 2, 4, 8, 6, 9, 0, 7, 1
// 9和0比较，9大在0后面：3, 5, 2, 4, 8, 6, 0, 9, 7, 1
// 9和7比较，9大在7后面：3, 5, 2, 4, 8, 6, 0, 7, 9, 1
// 9和1比较，9大在1后面：3, 5, 2, 4, 8, 6, 0, 7, 1, 9
// 
//对9进行排序，一共经历了9次；同理，对8进行排序，9已经排好只需要跟剩下8个数进行比较，所以要经历8次；
//以此类推，7经历7次，6经历6次，5经历5次，4经历4次，3经历3次，2经历2次，1经历1次，0经历0次


//void print_arr(int arr[], int sz)
//{
//	int i = 0;
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//	printf("\n");
//}
//
//void bubble_sort(int arr[], int sz)
//{
//	int i = 0;
//	//趟数
//	for (i = 0; i < sz - 1; i++)//数组有10个元素,由上面例子可知，i要最大进行9次循环；i是趟数
//	{
//		//一趟冒泡排序的细节
//		int flag = 1;//假设已经有序了
//		int j = 0;
//		for (j = 0; j < sz - 1 - i; j++)//j是下标，下标10-1-0就是下标为9，最大下标为9
//		{
//			if (arr[j] > arr[j + 1])//如果前一个元素大于后一个元素，则进行交换，确保较小的元素向前移动。
//			{
//				int tmp = arr[j];
//				arr[j] = arr[j + 1];
//				arr[j + 1] = tmp;
//				flag = 0;
//			}
//		}
//		if(flag == 1)//全部已排升序完成后则退出循环
//		{
//			break;
//		}
//	}
//}
//
//int main()
//{
//	int arr[] = { 3,1,5,2,4,8,6,0,7,9 };
//	//写一个函数，完成对arr数组的升序排序
//	//冒泡排序
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	print_arr(arr, sz);
//	bubble_sort(arr, sz);
//	print_arr(arr, sz);
//	return 0;
//}


//二级指针
//int main()
//{
//	int a = 5;
//	int* pa = &a;//pa 是指针变量，一级指针变量用来存放a变量的地址
//	int* paa = &pa;//ppa 就是二级指针变量，二级指针变量就是用来存放一级指针变量的地址
//	return 0;
//}


//指针数组
// 指针数组是用来存放指针的数组
// 意思是这个数组中存放的是指针，指针就是地址
// 
// 如：字符数组-->存放字符的数组-->char arr[5];
//     整型数组-->存放整型的数组-->int arr[6];

//int main()
//{
//	//int* arr1[5];//存放整型指针的数组
//	//char* arr2[6];//存放字符指针的数组
//
//	int a = 3;
//	int b = 4;
//	int c = 6;
//	int* arr[] = { &a,&b,&c };//指针数组
//	int i = 0;
//	for (i = 0; i < 3; i++)
//	{
//		printf("%d ", *(arr[i]));
//	}
//	return 0;
//}


//用指针数组模拟二位数组
//int main()
//{
//	int arr1[] = { 1,2,3,4,5 };
//	int arr2[] = { 2,3,4,5,6 };
//	int arr3[] = { 3,4,5,6,7 };
//	int* arr4[] = { arr1,arr2,arr3 };
//	int i = 0;
//	int j = 0;
//	for (i = 0; i < 3; i++)
//	{
//		for (j = 0; j < 5; j++)
//		{
//			printf("%d", arr4[i][j]);
//		}
//		printf("\n");
//	}
//	return 0;
//}
